﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using RayDen.Library.Components.Color.Types;
using RayDen.Library.Core.Primitives;
using RayDen.RayEngine.Core.Interface;

namespace RayDen.RayEngine.Core.Types {

    [Flags]
    public enum BxDFType : byte {
        Reflection = 1 << 0,
        Transmission = 1 << 1,
        Diffuse = 1 << 2,
        Glossy = 1 << 3,
        Specular = 1 << 4,
        AllTypes = Diffuse | Glossy | Specular,

        AllReflection = Reflection |AllTypes,
        AllTransmission = Transmission | AllTypes,
        All = AllReflection | AllTransmission
    }

    public class Sample {
        public double imageX, imageY;
        public int pass;
        public int modify;
        public int Index, Flags;
        private ISampler sampler;

        public float[] sampleData;
        public int[] modifyData;

        private readonly Stack<Tuple<int, float>> sampleStack;

        public Sample(ISampler sampler) {
            this.sampler = sampler;
            //sampleStack = new Stack<Tuple<int, float>>();
        }

        public void Push(int i)
        {
            this.sampleStack.Push(new Tuple<int, float>(modifyData[i], sampleData[i]));
        }

        public void ClearStack()
        {
            this.sampleStack.Clear();
        }

        public void Pop(int i)
        {
            var data = this.sampleStack.Pop();
            modifyData[i] = data.Item1;
            sampleData[i] = data.Item2;
        }

        public Sample(Sample sample)
        {
            this.sampler = sample.sampler;
            this.sampleData = sample.sampleData.ToArray();
            this.imageX = sample.imageX;
            this.pass = sample.pass;
            this.imageY = sample.imageY;
            this.Index = sample.Index;
        }

        public void InitSample(int dataDepth) {
            sampleData = new float[dataDepth];
            Index = 0;
            for (int i = 0; i < dataDepth; i++)
            {
                sampleData[i] = this.sampler.NextFloat();
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public float GetLazyValue(int index) {
            //if (index > sampleData.Length) {
            //    return this.GetLazyValue();
            //}
            return this.sampler.GetLazyValue(this, index);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public float GetLazyValue()
        {
            return this.sampler.GetLazyValue(this);
        }

        public float GetLDValue()
        {
            return this.sampler.GetLDValue(this);
        }
    }



    public class CameraSample
    {
        public float imageX, imageY;
        public float lensU, lensV;
        public float time;
        public RayData EyeRay;

    }

    public class LightSample
    {
        public float[] Spectra;
        public ISpectrum Spectrum;
        public IColorType Color;
        public float Lambda;

        public RayData LightRay;

        public float Pdf, Distance, U, V;
        public int LightIndex;
    }


    public struct VolumeSample
    {
        public RgbSpectrum Radiance;
        public float Transmittance;
        public Vector ScatteringDirection;
    }

    public class BsdfSample
    {
        public float[] SampleData;
        public float[] Spectrum;

        public Vector Wi;

        public float Pdf;

        public bool SpecularBounce;

        public BxDFType Bounce;

        public float RefractionScale;

        public static bool MatchesFlags(BxDFType obj, BxDFType flags)
        {
            return obj.HasFlag(flags);
            //return (flags & obj).Equals(flags) || (flags & obj).Equals(obj);
        }
    }


}
